package com.ruoyi.campus.controller;

import com.ruoyi.campus.service.IFileStorageService;
import com.ruoyi.campus.service.IMediaProcessService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 文件上传Controller
 * 
 * @author campus-alarm
 * @date 2024-01-01
 */
@RestController
@RequestMapping("/campus/file")
public class FileUploadController extends BaseController
{
    @Autowired
    private IFileStorageService fileStorageService;

    @Autowired
    private IMediaProcessService mediaProcessService;

    /**
     * 单文件上传
     */
    @Log(title = "文件上传", businessType = BusinessType.OTHER)
    @PostMapping("/upload")
    public AjaxResult uploadFile(@RequestParam("file") MultipartFile file,
                                @RequestParam(value = "folder", required = false, defaultValue = "common") String folder)
    {
        try
        {
            if (file.isEmpty())
            {
                return AjaxResult.error("上传文件不能为空");
            }

            // 验证文件类型和大小
            String result = validateFile(file);
            if (StringUtils.isNotEmpty(result))
            {
                return AjaxResult.error(result);
            }

            // 上传文件
            Map<String, Object> uploadResult = fileStorageService.uploadFile(file, folder);
            
            return AjaxResult.success("文件上传成功").put("data", uploadResult);
        }
        catch (Exception e)
        {
            logger.error("文件上传失败", e);
            return AjaxResult.error("文件上传失败：" + e.getMessage());
        }
    }

    /**
     * 多文件上传
     */
    @Log(title = "批量文件上传", businessType = BusinessType.OTHER)
    @PostMapping("/uploads")
    public AjaxResult uploadFiles(@RequestParam("files") MultipartFile[] files,
                                 @RequestParam(value = "folder", required = false, defaultValue = "common") String folder)
    {
        try
        {
            if (files == null || files.length == 0)
            {
                return AjaxResult.error("上传文件不能为空");
            }

            Map<String, Object> result = new HashMap<>();
            for (int i = 0; i < files.length; i++)
            {
                MultipartFile file = files[i];
                if (!file.isEmpty())
                {
                    // 验证文件
                    String validateResult = validateFile(file);
                    if (StringUtils.isNotEmpty(validateResult))
                    {
                        result.put("file_" + i + "_error", validateResult);
                        continue;
                    }

                    // 上传文件
                    Map<String, Object> uploadResult = fileStorageService.uploadFile(file, folder);
                    result.put("file_" + i, uploadResult);
                }
            }

            return AjaxResult.success("批量上传完成").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("批量文件上传失败", e);
            return AjaxResult.error("批量上传失败：" + e.getMessage());
        }
    }

    /**
     * 分片上传初始化
     */
    @PostMapping("/chunk/init")
    public AjaxResult initChunkUpload(@RequestParam("fileName") String fileName,
                                     @RequestParam("fileSize") Long fileSize,
                                     @RequestParam("chunkSize") Integer chunkSize,
                                     @RequestParam(value = "folder", required = false, defaultValue = "common") String folder)
    {
        try
        {
            Map<String, Object> result = fileStorageService.initChunkUpload(fileName, fileSize, chunkSize, folder);
            return AjaxResult.success("分片上传初始化成功").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("分片上传初始化失败", e);
            return AjaxResult.error("初始化失败：" + e.getMessage());
        }
    }

    /**
     * 分片上传
     */
    @PostMapping("/chunk/upload")
    public AjaxResult uploadChunk(@RequestParam("file") MultipartFile chunk,
                                 @RequestParam("uploadId") String uploadId,
                                 @RequestParam("chunkIndex") Integer chunkIndex)
    {
        try
        {
            Map<String, Object> result = fileStorageService.uploadChunk(chunk, uploadId, chunkIndex);
            return AjaxResult.success("分片上传成功").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("分片上传失败", e);
            return AjaxResult.error("分片上传失败：" + e.getMessage());
        }
    }

    /**
     * 合并分片文件
     */
    @PostMapping("/chunk/merge")
    public AjaxResult mergeChunks(@RequestParam("uploadId") String uploadId,
                                 @RequestParam("totalChunks") Integer totalChunks)
    {
        try
        {
            Map<String, Object> result = fileStorageService.mergeChunks(uploadId, totalChunks);
            return AjaxResult.success("文件合并成功").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("文件合并失败", e);
            return AjaxResult.error("文件合并失败：" + e.getMessage());
        }
    }

    /**
     * 图片压缩
     */
    @PostMapping("/image/compress")
    public AjaxResult compressImage(@RequestParam("file") MultipartFile file,
                                   @RequestParam(value = "quality", required = false, defaultValue = "0.8") Float quality,
                                   @RequestParam(value = "maxWidth", required = false) Integer maxWidth,
                                   @RequestParam(value = "maxHeight", required = false) Integer maxHeight)
    {
        try
        {
            if (!isImageFile(file))
            {
                return AjaxResult.error("只支持图片文件压缩");
            }

            Map<String, Object> result = mediaProcessService.compressImage(file, quality, maxWidth, maxHeight);
            return AjaxResult.success("图片压缩成功").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("图片压缩失败", e);
            return AjaxResult.error("图片压缩失败：" + e.getMessage());
        }
    }

    /**
     * 生成图片缩略图
     */
    @PostMapping("/image/thumbnail")
    public AjaxResult generateThumbnail(@RequestParam("file") MultipartFile file,
                                       @RequestParam(value = "width", required = false, defaultValue = "200") Integer width,
                                       @RequestParam(value = "height", required = false, defaultValue = "200") Integer height)
    {
        try
        {
            if (!isImageFile(file))
            {
                return AjaxResult.error("只支持图片文件生成缩略图");
            }

            Map<String, Object> result = mediaProcessService.generateThumbnail(file, width, height);
            return AjaxResult.success("缩略图生成成功").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("缩略图生成失败", e);
            return AjaxResult.error("缩略图生成失败：" + e.getMessage());
        }
    }

    /**
     * 音频转码
     */
    @PostMapping("/audio/convert")
    public AjaxResult convertAudio(@RequestParam("file") MultipartFile file,
                                  @RequestParam(value = "targetFormat", required = false, defaultValue = "mp3") String targetFormat,
                                  @RequestParam(value = "bitrate", required = false, defaultValue = "128") Integer bitrate)
    {
        try
        {
            if (!isAudioFile(file))
            {
                return AjaxResult.error("只支持音频文件转码");
            }

            Map<String, Object> result = mediaProcessService.convertAudio(file, targetFormat, bitrate);
            return AjaxResult.success("音频转码成功").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("音频转码失败", e);
            return AjaxResult.error("音频转码失败：" + e.getMessage());
        }
    }

    /**
     * 视频转码
     */
    @PostMapping("/video/convert")
    public AjaxResult convertVideo(@RequestParam("file") MultipartFile file,
                                  @RequestParam(value = "targetFormat", required = false, defaultValue = "mp4") String targetFormat,
                                  @RequestParam(value = "resolution", required = false, defaultValue = "720p") String resolution)
    {
        try
        {
            if (!isVideoFile(file))
            {
                return AjaxResult.error("只支持视频文件转码");
            }

            Map<String, Object> result = mediaProcessService.convertVideo(file, targetFormat, resolution);
            return AjaxResult.success("视频转码成功").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("视频转码失败", e);
            return AjaxResult.error("视频转码失败：" + e.getMessage());
        }
    }

    /**
     * 删除文件
     */
    @Log(title = "删除文件", businessType = BusinessType.DELETE)
    @DeleteMapping("/delete")
    @PreAuthorize("@ss.hasPermi('campus:file:delete')")
    public AjaxResult deleteFile(@RequestParam("filePath") String filePath)
    {
        try
        {
            boolean result = fileStorageService.deleteFile(filePath);
            if (result)
            {
                return AjaxResult.success("文件删除成功");
            }
            else
            {
                return AjaxResult.error("文件删除失败");
            }
        }
        catch (Exception e)
        {
            logger.error("文件删除失败", e);
            return AjaxResult.error("文件删除失败：" + e.getMessage());
        }
    }

    /**
     * 批量删除文件
     */
    @Log(title = "批量删除文件", businessType = BusinessType.DELETE)
    @DeleteMapping("/deletes")
    @PreAuthorize("@ss.hasPermi('campus:file:delete')")
    public AjaxResult deleteFiles(@RequestParam("filePaths") List<String> filePaths)
    {
        try
        {
            Map<String, Boolean> result = fileStorageService.deleteFiles(filePaths);
            return AjaxResult.success("批量删除完成").put("data", result);
        }
        catch (Exception e)
        {
            logger.error("批量删除文件失败", e);
            return AjaxResult.error("批量删除失败：" + e.getMessage());
        }
    }

    /**
     * 下载文件
     */
    @GetMapping("/download")
    public void downloadFile(@RequestParam("filePath") String filePath, HttpServletResponse response)
    {
        try
        {
            fileStorageService.downloadFile(filePath, response);
        }
        catch (Exception e)
        {
            logger.error("文件下载失败", e);
        }
    }

    /**
     * 获取文件信息
     */
    @GetMapping("/info")
    public AjaxResult getFileInfo(@RequestParam("filePath") String filePath)
    {
        try
        {
            Map<String, Object> fileInfo = fileStorageService.getFileInfo(filePath);
            return AjaxResult.success(fileInfo);
        }
        catch (Exception e)
        {
            logger.error("获取文件信息失败", e);
            return AjaxResult.error("获取文件信息失败：" + e.getMessage());
        }
    }

    /**
     * 验证文件
     */
    private String validateFile(MultipartFile file)
    {
        // 检查文件大小
        long maxSize = 100 * 1024 * 1024; // 100MB
        if (file.getSize() > maxSize)
        {
            return "文件大小超过限制(100MB)";
        }

        // 检查文件类型
        String fileName = file.getOriginalFilename();
        if (StringUtils.isEmpty(fileName))
        {
            return "文件名不能为空";
        }

        // 检查文件扩展名
        if (!FileUploadUtils.isAllowedExtension(fileName, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION))
        {
            return "不支持的文件类型";
        }

        return null;
    }

    /**
     * 判断是否为图片文件
     */
    private boolean isImageFile(MultipartFile file)
    {
        String fileName = file.getOriginalFilename();
        return StringUtils.isNotEmpty(fileName) && 
               FileUploadUtils.isAllowedExtension(fileName, MimeTypeUtils.IMAGE_EXTENSION);
    }

    /**
     * 判断是否为音频文件
     */
    private boolean isAudioFile(MultipartFile file)
    {
        String fileName = file.getOriginalFilename();
        return StringUtils.isNotEmpty(fileName) && 
               (fileName.toLowerCase().endsWith(".mp3") || 
                fileName.toLowerCase().endsWith(".wav") || 
                fileName.toLowerCase().endsWith(".m4a") ||
                fileName.toLowerCase().endsWith(".aac"));
    }

    /**
     * 判断是否为视频文件
     */
    private boolean isVideoFile(MultipartFile file)
    {
        String fileName = file.getOriginalFilename();
        return StringUtils.isNotEmpty(fileName) && 
               (fileName.toLowerCase().endsWith(".mp4") || 
                fileName.toLowerCase().endsWith(".avi") || 
                fileName.toLowerCase().endsWith(".mov") ||
                fileName.toLowerCase().endsWith(".wmv") ||
                fileName.toLowerCase().endsWith(".flv"));
    }
} 